package com.ljw.spring.annotation.conf;

import com.ljw.spring.annotation.bean.Car;
import com.ljw.spring.annotation.bean.Color;
import com.ljw.spring.annotation.bean.Dog;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.*;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.inject.Inject;

/**
 * @FileName ConfigOfAutowired
 * @Description TODO 自动装配：spring利用依赖注入（DI）完成对IOC容器中各个组件依赖关系的赋值
 *          1. @Autowired(required = true)  必须在被@Component、@Service等标注的类中使用才有效;
 *                  required = true:默认true。表示必须在IOC容器中找到对应类型的组件，否则报错
 *                  required = false：不必须，找不到也不会报错
 *              （1）默认优先按照类型去IOC容器中去找对应的组件
 *              （2）如果找到多个同类型的组件，报错NoUniqueBeanDefinitionException
 *                  解决：1. 使用@Bean注册组件时，添加注解@Primary：表示以这个为首选
 *                          @Bean(value = {"dog"})
 *                          @Primary
 *                       2.  @Autowired 和  @Qualifier(value = "dog") 一起使用：明确指定获取哪个bean
 *          2. spring还支持使用 @Resource[JSR250规范] 和 @Inject[JSR330规范] 【java标准规范】
 *              @Resource(name = "dog")：默认按照组件名（即组件id）获取IOC容器中对应的组件,忽略掉了@Primary的功能
 *              javax.inject：
 *                      需要导入javax.inject这个jar包。其功能和@Autowired一样
 *           3.  @Autowired 可标注在 构造器、方法、参数、属性字段上：方法参数组件和属性组件都会从IOC容器获取对应的实例对象
 *              （1）@Autowired标注在方法上，方法参数会从IOC容器获取对应的组件,并为参数赋值
 *              （2）IOC容器启动时，IOC容器中类的组件默认调用无参构造创建实例对象；
 *                  当把@Autowired标注在一个类的有参构造函数上时，IOC容器中这个类的组件就会调用有参构造创建其实例对象；
 *                  当类只有一个有参构造函数时，有参构造上的@Autowired可以省略，但参数组件还是自动从IOC容器中获取
 *              （3）用@Bean向容器添加组件时，方法参数组件是自动从IOC容器中获取对应的实例对象。@Autowired写不写都可以
 *
 *
 *           4. 自定义组件想要使用spring底层的组件（如ApplicationContextAware,BeanNameAware,EmbeddedValueResolverAware,MessageSourceAware等等）：
 *                  只需要自定义组件实现xxxAware接口，重写方法，则自定义组件在创建实例对象时，就会自动调用重写的方法注入相关spring底层组件。
 *                  如我的自定义类Boat中自动注入spring底层组件：ApplicationContext组件
 *                  自定义类Computer中自动注入spring底层组件：ApplicationContextAware,BeanNameAware,EmbeddedValueResolverAware,MessageSourceAware
 *                  xxxAware的功能是由xxxProcessor完成的，如ApplicationContextAware===》ApplicationContextAwareProcessor
 *
 *              注解AutowiredAnnotationBeanPostProcessor解析自动装配注解@Autowired、@Inject等
 *
 * @Author ljw
 * @Date 2021/2/2 23:43
 * @Version 1.0
 */
@Configuration
@ComponentScan(basePackages = {"com.ljw.spring.annotation.bean"})
@PropertySource(value = {"classpath:/dog.properties"})
public class ConfigOfAutowired {


    @Bean(value = {"dog"})
    @Primary
    public Dog getDog() {
        System.out.println("创建Dog实例");
        return new Dog("lucky",2,"1.2");
    }

    @Bean(value = {"dog1"})
    public Dog getDog1() {
        System.out.println("创建Dog实例1");
        return new Dog("lucky",1,"0.6");
    }

    @Bean
    public Color getColor(){
        return new Color();
    }


    /**
     * @Bean向容器添加组件时，方法参数是自动从IOC容器中获取对应的组件
     * @param color
     * @return
     */
    @Bean
    public Car getCar(Color color){
        return new Car(2.3, color);
    }
}
